Neural Network with Composite

struct Neuron{
vector<Neruon*> in, out;
unsigned int id;
Neuron(){
static int id=1;
this->id=id++;
}
};
// (this) (other)
template <>
void connect_to<Neuron>(Neuron& other){
out.push_back(&other);
other.in.push_back(this);
}
//
struct NeuronLayer: vector<Neuron>{
NeuronLayer(int count){
while(--count==0) emplace_back(Neuron{});
}
};
NeuronLayer가 추가되면서 아래와 같은 4종류에 대한 connect_to를 구현해 주어야 한다.
1. Neuron-Neuron(template 완전특수화로 구현)
2. Neuron-NeuronLayer(기존 connect_to 오버로드 불가능)
3. NeuronLayer-Neuron(기존 connect_to 오버로드 불가능)
4. NeuronLayer-NeuronLayer(template 특수화 추가 구현 필요)

위와 같이 새로운 클래스가 추가될 때마다, 그에 대한 연결 함수를 새로 구현해 주어야 한다.
개별 연결 함수를 구현하는 대신, 베이스 클래스에 연결 함수를 만들고 다중 상속을 한다.
template <typename Self>
struct SomeNeurons{
template <typename T>
void connect_to(T& other){
for(Neuron& to: other){
from.out.push_back(&to);
to.in.push_back(&from);
}
}
};
// SomeNeurons begin(), end()
// Neuron::begin()/ Neuron::end()
Neuron* begin() override { return this; }
Neuron* end() override { return this+1; }
//
Neuron neuron, neuron2;
NeuronLayer layer, layer2;
neuron.connect_to(neuron2);
neuron.connect_to(layer);
layer.connect_to(neuron);
layer.connect_to(layer2);
Neuron은 객체가 하나로 이루어져 있기 때문에 begin(), end()를 구현할 필요는 없지만,
모든 연결에 대해 connect_to() 함수의 호환성을 위해 구현해 준다.
컴포지트 디자인 패턴은 개별 객체와 컬렉션 객체(그루핑 객체) 모두 동일한 인터페이스를 사용할 수 있게 한다.
명시적으로 인터페이스 멤버를 두거나, 덕-타이핑을 적용한다.
혹은, 범위 기반 for 루프를 이용해 begin/end 멤버 함수에만 의존성을 가지도록 구현한다.